package com.bootdo.elasticsearch.query;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bootdo.common.utils.R;
import com.bootdo.elasticsearch.util.EsResult;
import com.bootdo.elasticsearch.util.EsSearch;
import io.swagger.annotations.ApiOperation;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.entity.ContentType;
import org.apache.http.nio.entity.NStringEntity;
import org.apache.http.util.EntityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.*;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.support.replication.ReplicationResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.VersionType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author wukq
 * @Date: 2020/4/26 16:36
 * @Description: 强烈建议从TransportClient迁移到RestClient，因为业务压测发现TransportClient存在并发瓶颈。
 * 在service里然后使用之前创建的highLevelClient呢？
 * <p>
 * es数据如何分页查询？
 * es数据如何关联几张表查询？
 */
@Controller
@RequestMapping("/system/es")
public class QueryESController {


    // @Autowired
    // private TransportClient transportClient;


    @Autowired
    RestHighLevelClient highLevelClient;

    @Value("${esConfig.connectionTimeOut}")
    private Integer connectionTimeOut;

    @Autowired
    private EsSearch esSearch;


    @ApiOperation(value = "查询es", notes = "")
    @ResponseBody
    @GetMapping("/getBookList")
    @RequiresPermissions("system:sysDept:sysDept")
    public R list(@RequestParam(name = "id", defaultValue = "") String id) {
        // new SearchRequest("book") 根据索引查询，没有索引，查询全部的
        SearchRequest searchRequest = new SearchRequest("book");//索引，相当与数据库
        searchRequest.types("man");//类型，相当于表
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchQuery("bookname", "伯爵"));//match查询不严格
        //sourceBuilder.query(QueryBuilders.termQuery("bookname", "伯爵"));//term查询时强制匹配过滤，很严格，bookname没有是伯爵的
        //sourceBuilder.query(QueryBuilders.termQuery("price", "50"));//查询价格是50的
        //sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        sourceBuilder.timeout(new TimeValue(connectionTimeOut, TimeUnit.MILLISECONDS));
        searchRequest.source(sourceBuilder);

        try {
            SearchResponse response = highLevelClient.search(searchRequest);
            Arrays.stream(response.getHits().getHits())
                    .forEach(i -> {
                        System.out.println("index:" + i.getIndex());
                        System.out.println("score:" + i.getScore());
                        System.out.println("sourceAsMap:" + i.getSourceAsMap());
                        System.out.println("String:" + i.getSourceAsString());
                        System.out.println("type:" + i.getType());

                    });
            System.out.println(response.getHits().totalHits);
            return R.ok();
        } catch (IOException e) {
            e.printStackTrace();
            return R.error();
        }
    }

    @ApiOperation(value = "根据id查询es2", notes = "")
    @ResponseBody
    @GetMapping("/getBookById")
    @RequiresPermissions("system:sysDept:sysDept")
    public R getBookById(@RequestParam(name = "id", defaultValue = "") String id) {
        // new SearchRequest("book") 根据索引查询，没有索引，查询全部的
        SearchRequest searchRequest = new SearchRequest("people");//索引，相当与数据库
        searchRequest.types("man");//类型，相当于表
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //sourceBuilder.query(QueryBuilders.matchPhrasePrefixQuery("country", "china"));//match_phrase短语匹配,比价严格，chinaTown没查出来
        sourceBuilder.query(QueryBuilders.termQuery("_id", id));//根据id查询,es自定义的id是_id，如果要用id，则要新建id
        //sourceBuilder.sort("age", SortOrder.DESC);//排序
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        sourceBuilder.timeout(new TimeValue(connectionTimeOut, TimeUnit.MILLISECONDS));
        searchRequest.source(sourceBuilder);

        try {
            SearchResponse response = highLevelClient.search(searchRequest);
//            Arrays.stream(response.getHits().getHits())
//                    .forEach(i -> {
//                        System.out.println("index:" + i.getIndex());//index:people
//                        System.out.println("score:" + i.getScore());//score:1.0
//                        System.out.println("sourceAsMap:" + i.getSourceAsMap());//sourceAsMap:{date=1997-3-14, country=china, name=王五, age=30}
//                        System.out.println("String:" + i.getSourceAsString());//String:{"name":"王五","country":"china","age":"30","date":"1997-3-14"}
//                        System.out.println("type:" + i.getType());//type:man
//
//                    });

            SearchHit[] hits = response.getHits().getHits();
            for (SearchHit i : hits) {
                System.out.println("index:" + i.getIndex());//index:people
                System.out.println("score:" + i.getScore());//score:1.0
                System.out.println("sourceAsMap:" + i.getSourceAsMap());//sourceAsMap:{date=1997-3-14, country=china, name=王五, age=30}
                System.out.println("String:" + i.getSourceAsString());//String:{"name":"王五","country":"china","age":"30","date":"1997-3-14"}
                System.out.println("type:" + i.getType());//type:man
            }

            System.out.println(response.getHits().totalHits); //1
            return R.ok();
        } catch (IOException e) {
            e.printStackTrace();
            return R.error();
        }
    }

    /**
     * 可以新增数据
     */
    @ApiOperation(value = "新增数据", notes = "")
    @ResponseBody
    @GetMapping("/addBook")
    @RequiresPermissions("system:sysDept:sysDept")
    public R addBook() throws IOException {
        Map<String, Object> bookMap = new HashMap<>();
        bookMap.put("user_id", 7);
        bookMap.put("username", "小张");
        bookMap.put("password", "123456");
        bookMap.put("company_name", "文化部");
        bookMap.put("age", 42);
        bookMap.put("address", "建设路四条街33号320");
        //SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //增, source 里对象创建方式可以是JSON字符串，或者Map，或者XContentBuilder 对象
        IndexRequest indexRequest = new IndexRequest("book", "user", "7");//.source(sourceBuilder)
        indexRequest.source(bookMap);
        IndexResponse indexResponse = highLevelClient.index(indexRequest);

        String index = indexResponse.getIndex();
        String type = indexResponse.getType();
        String id = indexResponse.getId();
        long version = indexResponse.getVersion();
        if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
            System.out.println("添加成功");
            System.out.println("type:" + type);
            System.out.println("id:" + id);
            System.out.println("version:" + version);
            System.out.println("index:" + index);
        }

        return R.ok();
    }

    /**
     * 可以更新数据,都是通过map添加和更新数据
     * 这个是同步方法
     */
    @ApiOperation(value = "更新数据", notes = "")
    @ResponseBody
    @GetMapping("/updateBook")
    @RequiresPermissions("system:sysDept:sysDept")
    public R updateBook() throws IOException {
        Map<String, Object> bookMap = new HashMap<>();
        bookMap.put("user_id", 7);
        bookMap.put("username", "小张");
        bookMap.put("password", "123456");
        bookMap.put("company_name", "建设部");
        bookMap.put("age", 50);
        bookMap.put("address", "建设路四条街30号400");
        //SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //增, source 里对象创建方式可以是JSON字符串，或者Map，或者XContentBuilder 对象
        UpdateRequest updateRequest = new UpdateRequest("book", "user", "7").doc(bookMap);//.source(sourceBuilder)
        UpdateResponse updateResponse = highLevelClient.update(updateRequest);

        DocWriteResponse.Result result = updateResponse.getResult();


        String index = updateResponse.getIndex();
        String type = updateResponse.getType();
        String id = updateResponse.getId();
        long version = updateResponse.getVersion();
        if (result == DocWriteResponse.Result.UPDATED) {
            System.out.println("更新成功");
            System.out.println("index:" + index);
            System.out.println("type:" + type);
            System.out.println("id:" + id);
            System.out.println("version:" + version);

        }

        return R.ok();
    }


    /**
     * 使用EsSearch查询
     */
    @ApiOperation(value = "使用EsSearch查询", notes = "")
    @ResponseBody
    @GetMapping("/esSearch")
    @RequiresPermissions("system:sysDept:sysDept")
    public R esSearch() throws Exception {
        List<Integer> idList = new ArrayList<>();
        idList.add(1);
        idList.add(2);
        idList.add(3);
        idList.add(4);
        idList.add(5);

        List<Long> idList2 = new ArrayList<>();
        idList2.add(1L);
        idList2.add(2L);
        idList2.add(3L);
        idList2.add(4L);
        idList2.add(5L);
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        /*
        当使用到term 查询的时候，由于是精准匹配，所以查询的关键字在es上的类型，必须是keyword而不能是text，
        比如你的搜索条件是 ”name”:”蔡虚坤”,那么该name 字段的es类型得是keyword，而不能是text
         * */
        //queryBuilder.must(QueryBuilders.termQuery("_id", idList));//可以查询，但是没结果。termQuery查询的字段必须是keyword,_id是es的关键字
        //queryBuilder.must(QueryBuilders.termQuery("user_id", idList));//报错，user_id不是keyword

        //queryBuilder.must(QueryBuilders.matchQuery("user_id", idList2));//报错


        queryBuilder.must(QueryBuilders.matchQuery("company_name", "智慧工匠"));//查询有结果,查询结果被转换成驼峰了
        //{password=123456, address=中南路吉庆街1101号29栋704, companyName=智慧工匠, userId=2, age=18, username=阿强}


        String[] columns = new String[]{"user_id", "username", "password", "company_name", "age", "address"};//需要查询的字段
        String[] excludes = Strings.EMPTY_ARRAY;//过滤掉哪些字段

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        searchSourceBuilder.fetchSource(columns, excludes);

        EsResult<Map<String, Object>> esResult = esSearch.getEsResult(searchSourceBuilder, 1, 10, "book");
        List<Map<String, Object>> resultList = esResult.getEsResultList();

        for (Map<String, Object> map : resultList) {
            System.out.println(map.toString());
        }

        return R.ok();
    }

    /**
     * 参考：
     * 三、异步请求：https://blog.csdn.net/qq_2300688967/article/details/83792636
     * <p>
     * 1）创建异步请求的，回调对象：ActionListener<IndexResponse>
     * <p>
     * 如果执行成功，会自动调用onResponse方法，如果执行失败，会回调onFailure方法
     * <p>
     * 可以从传入的IndexResponse和Exception类型参数中获取相关创建情况信息
     */
    public void exampleUpdate() {

        ActionListener<IndexResponse> listener = new ActionListener<IndexResponse>() {
            @Override
            public void onResponse(IndexResponse indexResponse) {
                String index = indexResponse.getIndex();
                String type = indexResponse.getType();
                String id = indexResponse.getId();
                long version = indexResponse.getVersion();
                if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
                    System.out.println("添加成功");
                    System.out.println("type:" + type);
                    System.out.println("id:" + id);
                    System.out.println("version:" + version);
                    System.out.println("index:" + index);
                } else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
                    System.out.println("更新成功");
                    System.out.println("index:" + index);
                    System.out.println("type:" + type);
                    System.out.println("id:" + id);
                    System.out.println("version:" + version);
                }
                ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
                if (shardInfo.getTotal() != shardInfo.getSuccessful()) {

                }
                if (shardInfo.getFailed() > 0) {
                    for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
                        String reason = failure.reason();
                    }
                }
            }

            @Override
            public void onFailure(Exception e) {
                e.printStackTrace();
            }
        };
    }


    /**
     * 增删查改,没有涉及到具体代码
     */
    public void example() throws IOException {
        Map<String, Object> builder = new HashMap<>();
        //增, source 里对象创建方式可以是JSON字符串，或者Map，或者XContentBuilder 对象
        IndexRequest indexRequest = new IndexRequest("指定index", "指定type", "指定ID").source(builder);
        IndexResponse indexResponse = highLevelClient.index(indexRequest);
        if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
            System.out.println("添加成功");
            System.out.println("type:" + indexResponse.getType());
            System.out.println("id:" + indexResponse.getId());
            System.out.println("version:" + indexResponse.getVersion());
            System.out.println("index:" + indexResponse.getIndex());
        }

        //删
        DeleteRequest deleteRequest = new DeleteRequest("指定index", "指定type", "指定ID");
        DeleteResponse deleteResponse = highLevelClient.delete(deleteRequest);
        if (deleteResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) {
            System.out.println("未找到需要删除的文档!");
            return;
        }


        //改, source 里对象创建方式可以是JSON字符串，或者Map，或者XContentBuilder 对象
        UpdateRequest updateRequest = new UpdateRequest("指定index", "指定type", "指定ID").doc(builder);
        UpdateResponse updateResponse = highLevelClient.update(updateRequest);
        if (updateResponse.getResult() == DocWriteResponse.Result.UPDATED) {
            System.out.println("更新成功");
            System.out.println("type:" + updateResponse.getType());
            System.out.println("id:" + updateResponse.getId());
            System.out.println("version:" + updateResponse.getVersion());
            System.out.println("index:" + updateResponse.getIndex());
        }


        //查
        GetRequest getRequest = new GetRequest("指定index", "指定type", "指定ID");
        GetResponse getResponse = highLevelClient.get(getRequest);
        if (getResponse.isExists()) {
            long version = getResponse.getVersion();
            String sourceAsString = getResponse.getSourceAsString();
            System.out.println("version:" + version + "，内容字符串：" + sourceAsString);
            Map<String, Object> sourceAsMap = getResponse.getSourceAsMap();
            byte[] sourceAsBytes = getResponse.getSourceAsBytes();

        } else {
            System.out.println("所查询的文档不存在！");
        }

    }

    /**
     * 用sql查询的示例代码
     */
    public void exampleSql() {
        Map<String, String> params = Collections.emptyMap();
        RestClient restClient = RestClient
                .builder(new HttpHost("172.18.90.40", 9200, "http"))
                .build();

        String queryString = "{" +
                "  \"size\": 20," +
                "  \"query\": {" +
                "   \"range\": {" +
                "     \"createTime\": {" +
                "       \"gte\": \"2018-06-01 00:00:00\"" +
                "     }" +
                "   }" +
                "  }" +
                "}";

        HttpEntity entity = new NStringEntity(queryString, ContentType.APPLICATION_JSON);

        try {

            Response response = restClient.performRequest("GET", "/some_important_index*/_search", params, entity);
            System.out.println(response.getStatusLine().getStatusCode());
            String responseBody = null;

            responseBody = EntityUtils.toString(response.getEntity());
            System.out.println("******************************************** ");

            JSONObject jsonObject = JSON.parseObject(responseBody);


            System.out.println(jsonObject.get("hits"));
        } catch (ResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("23333");
    }

    /**
     * 同步查询例子
     * 1，执行方法：
     * GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
     * <p>
     * 2，根据返回的结果：
     * <p>
     * a.判断文档是否存在：
     * <p>
     * getResponse.isExists()，如果为true，则存在
     * b.将查询的文档内容转成字符串：
     * <p>
     * String sourceAsString = getResponse.getSourceAsString();
     * c.将查询的文档内容转换成Map对象：
     * <p>
     * Map<String, Object> sourceAsMap = getResponse.getSourceAsMap();
     * ————————————————
     * 版权声明：本文为CSDN博主「未名who」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
     * 原文链接：https://blog.csdn.net/qq_2300688967/article/details/83818289
     */
    public void queryExample() throws IOException {
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("127.0.0.1", 9200, "http")
                )
        );


        GetRequest getRequest = new GetRequest("posts", "doc", "16");
        getRequest.version(4);
        String[] includes = new String[]{"message", "*Date"};
        String[] excludes = Strings.EMPTY_ARRAY;
        FetchSourceContext fetchSourceContext =
                new FetchSourceContext(true, includes, excludes);
        getRequest.fetchSourceContext(fetchSourceContext);

        try {
            GetResponse getResponse = client.get(getRequest);//, RequestOptions.DEFAULT
            String index = getResponse.getIndex();
            String type = getResponse.getType();
            String id = getResponse.getId();
            System.out.println("index:" + index + "; type:" + type + "; id:" + id);
            if (getResponse.isExists()) {
                long version = getResponse.getVersion();
                String sourceAsString = getResponse.getSourceAsString();
                System.out.println("version:" + version + "，内容字符串：" + sourceAsString);
                Map<String, Object> sourceAsMap = getResponse.getSourceAsMap();
                byte[] sourceAsBytes = getResponse.getSourceAsBytes();
            } else {
                System.out.println("所查询的文档不存在！");
            }
        } catch (ElasticsearchException e) {
            if (e.status() == RestStatus.NOT_FOUND) {
                System.out.println("所查询的文档库不存在！");
            } else if (e.status() == RestStatus.CONFLICT) {
                System.out.println("与当前版本冲突");
            }
        }

    }

    /**
     * elasticsearch（五）java 使用批量操作bulk及注意事项
     * https://blog.csdn.net/qq_2300688967/article/details/83861360
     */
    public void example5() {
        try (RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("127.0.0.1", 9200, "http")
                )
        )) {

            BulkRequest bulkRequest = new BulkRequest();
            bulkRequest.add(new IndexRequest("posts", "doc", "5").source(XContentType.JSON, "field", "foo").opType(DocWriteRequest.OpType.CREATE));
            bulkRequest.add(new IndexRequest("posts2000", "doc", "2").source(XContentType.JSON, "field", "bar"));
            bulkRequest.add(new IndexRequest("posts", "doc", "3").source(XContentType.JSON, "field", "baz"));

            bulkRequest.add(new DeleteRequest("posts", "doc", "300"));
            bulkRequest.add(new UpdateRequest("posts", "doc", "2").doc(XContentType.JSON, "other", "test").fetchSource(true));
            bulkRequest.add(new IndexRequest("posts", "doc", "4").source(XContentType.JSON, "field", "baz"));

            bulkRequest.timeout(TimeValue.timeValueMinutes(2));
            bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
            BulkResponse bulkResponse = client.bulk(bulkRequest);//, RequestOptions.DEFAULT

            for (BulkItemResponse bulkItemResponse : bulkResponse) {
                if (bulkItemResponse.getFailure() != null) {
                    BulkItemResponse.Failure failure = bulkItemResponse.getFailure();
                    System.out.println(failure.getCause());
                    if (failure.getStatus() == RestStatus.BAD_REQUEST) {
                        System.out.println("id=" + bulkItemResponse.getId() + "为非法的请求!");
                        continue;
                    }
                }

                DocWriteResponse itemResponse = bulkItemResponse.getResponse();

                if (bulkItemResponse.getOpType() == DocWriteRequest.OpType.INDEX || bulkItemResponse.getOpType() == DocWriteRequest.OpType.CREATE) {
                    if (bulkItemResponse.getFailure() != null && bulkItemResponse.getFailure().getStatus() == RestStatus.CONFLICT) {
                        System.out.println("id=" + bulkItemResponse.getId() + "与现在文档冲突");
                        continue;
                    }
                    IndexResponse indexResponse = (IndexResponse) itemResponse;
                    System.out.println("id=" + indexResponse.getId() + "的文档创建成功");
                    System.out.println("id=" + indexResponse.getId() + "文档操作类型：" + itemResponse.getResult());
                } else if (bulkItemResponse.getOpType() == DocWriteRequest.OpType.UPDATE) {
                    UpdateResponse updateResponse = (UpdateResponse) itemResponse;
                    System.out.println("id=" + updateResponse.getId() + "的文档更新成功");
                    System.out.println("id=" + updateResponse.getId() + "文档内容为：" + updateResponse.getGetResult().sourceAsString());
                } else if (bulkItemResponse.getOpType() == DocWriteRequest.OpType.DELETE) {
                    DeleteResponse deleteResponse = (DeleteResponse) itemResponse;
                    if (deleteResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) {
                        System.out.println("id=" + deleteResponse.getId() + "的文档未找到，未执行删除!");
                    } else {
                        System.out.println("id=" + deleteResponse.getId() + "的文档删除成功");
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /***
     * elasticsearch（六）java 使用批量查询multiGet介绍及使用
     * https://blog.csdn.net/qq_2300688967/article/details/83867140
     */
    public void example6() {
        try (RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("127.0.0.1", 9200, "http")
                )
        )) {
            // 创建查询父对象
            MultiGetRequest request = new MultiGetRequest();
            // 添加子查询
            request.add(new MultiGetRequest.Item("posts", "doc", "1"));
            request.add(new MultiGetRequest.Item("posts", "doc2", "2").fetchSourceContext(FetchSourceContext.DO_NOT_FETCH_SOURCE));
            String[] includes = new String[]{"user", "*r"};
            String[] excludes = Strings.EMPTY_ARRAY;
            FetchSourceContext fetchSourceContext = new FetchSourceContext(true, includes, excludes);
            request.add(new MultiGetRequest.Item("posts2", "doc", "3").fetchSourceContext(fetchSourceContext));
//            // user必须在map集合中
//            request.add(new MultiGetRequest.Item("posts", "doc", "4")
//                    .storedFields("user"));
//            MultiGetResponse response = client.mget(request, RequestOptions.DEFAULT);
//            MultiGetItemResponse item = response.getResponses()[0];
//            // user必须在map集合中
//            String value = item.getResponse().getField("user").getValue();

            // 针对每个子请求分别设置，无法在主请求中设置
            // 指定去哪个分片上查询，如何指定分片上没有，不会再去其它分片查询，如果不指定，则依次轮询各个分片查询
            request.add(new MultiGetRequest.Item("posts", "doc", "with_routing")
                    .routing("some_routing"));
            request.add(new MultiGetRequest.Item("index", "type", "with_parent")
                    .parent("some_parent"));
            request.add(new MultiGetRequest.Item("index", "type", "with_version")
                    .versionType(VersionType.EXTERNAL)
                    .version(10123L));
            // preference, realtime and refresh 需要在主请求里设置，子请求中无法设置
            request.preference("some_preference");
            // realtime的值默认为true
            request.realtime(false);
            request.refresh(true);
            MultiGetResponse response = client.multiGet(request);//, RequestOptions.DEFAULT
            int count = 0;
            for (MultiGetItemResponse item : response.getResponses()) {
                String index = item.getIndex();
                String type = item.getType();
                String id = item.getId();
                System.out.println("第" + ++count + "条-》index:" + index + "; type:" + type + "; id:" + id);
                if (item.getFailure() != null) {
                    Exception e = item.getFailure().getFailure();
                    ElasticsearchException ee = (ElasticsearchException) e;
                    if (ee.getMessage().contains("reason=no such index")) {
                        System.out.println("查询的文档库不存在！");
                    }
                }

                GetResponse getResponse = item.getResponse();

                if (getResponse.isExists()) {
                    long version = getResponse.getVersion();
                    String sourceAsString = getResponse.getSourceAsString();
                    System.out.println("查询的结果为：");
                    System.out.println(sourceAsString);
                    Map<String, Object> sourceAsMap = getResponse.getSourceAsMap();
                    byte[] sourceAsBytes = getResponse.getSourceAsBytes();
                } else {
                    System.out.println("没有查询到相应文档");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * elasticsearch（七）java 搜索功能Search Request的介绍与使用
     * https://blog.csdn.net/qq_2300688967/article/details/83902943
     */
    public void example7() {
        // 1）查询包含指定的内容：
        //查询所有的内容
        //searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        //b.查询包含关键词字段的文档：如下，表示查询出来所有包含user字段且user字段包含kimchy值的文档
        //sourceBuilder.query(QueryBuilders.matchAllQuery());

        SearchRequest searchRequest = new SearchRequest();
        //创建  搜索内容参数设置对象:SearchSourceBuilder
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //b将SearchSourceBuilder对象添加到搜索请求中:
        searchRequest.source(searchSourceBuilder);


        //查询包含关键词字段的文档：如下，表示查询出来所有包含user字段且user字段包含kimchy值的文档

        searchSourceBuilder.query(QueryBuilders.termQuery("user", "kimchy"));
        MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("user", "kimchy");
        // 启动模糊查询
        matchQueryBuilder.fuzziness(Fuzziness.AUTO);
        // 在匹配查询上设置前缀长度选项
        matchQueryBuilder.prefixLength(3);
        // 设置最大扩展选项以控制查询的模糊过程
        matchQueryBuilder.maxExpansions(10);


        //也可以使用QueryBuilders实用程序类创建QueryBuilder对象。此类提供了可用于使用流畅的编程样式创建QueryBuilder对象的辅助方法：
        QueryBuilder queryBuilder = QueryBuilders.matchQuery("user", "kimchy")
                .fuzziness(Fuzziness.AUTO)
                .prefixLength(3)
                .maxExpansions(10);


        //设置查询的起始索引位置和数量：如下表示从第1条开始，共返回5条文档数据
//        sourceBuilder.from(0);
//        sourceBuilder.size(5);
        //设置查询请求的超时时间：如下表示60秒没得到返回结果时就认为请求已超时
        // sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
    }
}
